/*
 * @Copyright: Copyright (c) 2030 吴周海
 * @Author: wzh200x@126.com
 * @Date: 2025-10-28 10:18:52
 * @LastEditors: wzh200x@126.com
 * @LastEditTime: 2025-10-28 13:50:53
 * @FilePath: \gogamewebserver\goGameWebServer\internal\middlewares\signature.go
 * @Description: 文件功能描述
 */
package middlewares

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"goGameWebServer/internal/common/config"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
)

// calculateSignature 计算签名
// 签名规则：按照key=value&key=value的格式拼接所有参数（按key字母顺序排序），
// 然后加上签名密钥，最后计算MD5值
func calculateSignature(params map[string][]string, secretKey string) string {
	// 创建一个新的参数映射，排除sign参数
	paramsWithoutSign := make(url.Values)
	for key, values := range params {
		if key != "sign" {
			paramsWithoutSign[key] = values
		}
	}

	// 获取所有参数的key并排序
	keys := make([]string, 0, len(paramsWithoutSign))
	for key := range paramsWithoutSign {
		keys = append(keys, key)
	}
	sort.Strings(keys)

	// 按照key=value&key=value的格式拼接参数
	var builder strings.Builder
	for i, key := range keys {
		if i > 0 {
			builder.WriteString("&")
		}
		builder.WriteString(key)
		builder.WriteString("=")
		builder.WriteString(paramsWithoutSign.Get(key))
	}

	// 加上签名密钥
	builder.WriteString(secretKey)

	// 计算MD5
	data := builder.String()
	hash := md5.Sum([]byte(data))
	return hex.EncodeToString(hash[:])
}

// GenerateSignature 生成签名（用于测试和调试）
func GenerateSignature(params map[string]string, secretKey string) (string, string) {
	// 当前时间戳
	timeStamp := fmt.Sprintf("%d", time.Now().Unix())

	// 添加时间戳到参数中
	paramsCopy := make(map[string]string)
	for k, v := range params {
		paramsCopy[k] = v
	}
	paramsCopy["time"] = timeStamp

	// 转换为url.Values格式
	urlValues := make(url.Values)
	for k, v := range paramsCopy {
		urlValues.Add(k, v)
	}

	// 计算签名
	sign := calculateSignature(urlValues, secretKey)

	// 返回时间戳和签名
	return timeStamp, sign
}

func SignatureMiddleware(r *ghttp.Request) {
	if config.AppOptions.ServerKey == "" || !config.AppOptions.CheckSign {
		r.Middleware.Next()
	} else {
		GoFrameSignatureMiddleware(config.AppOptions.ServerKey)(r)
	}
}

// GoFrameSignatureMiddleware GoFrame 签名校验中间件
func GoFrameSignatureMiddleware(secretKey string) func(r *ghttp.Request) {
	return func(r *ghttp.Request) {
		// 从查询参数中获取签名和时间戳
		clientSign := r.Get("sign").String()
		timestampStr := r.Get("time").String()

		if clientSign == "" || timestampStr == "" {
			r.SetParam("code", 401)
			r.SetParam("message", "缺少签名或时间戳参数")
			r.SetParam("data", g.Map{
				"error": "missing_signature_or_timestamp",
			})
			r.Response.WriteJsonExit(g.Map{
				"code":    401,
				"message": "缺少签名或时间戳参数",
				"data":    g.Map{"error": "missing_signature_or_timestamp"},
			})
			return
		}

		// 校验时间戳
		timestamp, err := strconv.ParseInt(timestampStr, 10, 64)
		if err != nil {
			r.SetParam("code", 401)
			r.SetParam("message", "无效的时间戳参数")
			r.SetParam("data", g.Map{
				"error": "invalid_timestamp",
			})
			r.Response.WriteJsonExit(g.Map{
				"code":    401,
				"message": "无效的时间戳参数",
				"data":    g.Map{"error": "invalid_timestamp"},
			})
			return
		}

		// 检查时间戳是否在5分钟内
		if time.Now().Unix()-timestamp > 300 {
			r.SetParam("code", 401)
			r.SetParam("message", "请求已过期")
			r.SetParam("data", g.Map{
				"error": "request_expired",
			})
			r.Response.WriteJsonExit(g.Map{
				"code":    401,
				"message": "请求已过期",
				"data":    g.Map{"error": "request_expired"},
			})
			return
		}

		// 获取所有查询参数
		queryParams := r.URL.Query()

		// 计算服务器端签名
		serverSign := calculateSignature(queryParams, secretKey)

		// 比较签名
		if clientSign != serverSign {
			r.SetParam("code", 401)
			r.SetParam("message", "无效的签名")
			r.SetParam("data", g.Map{
				"error": "invalid_signature",
			})
			r.Response.WriteJsonExit(g.Map{
				"code":    401,
				"message": "无效的签名",
				"data":    g.Map{"error": "invalid_signature"},
			})
			return
		}

		r.Middleware.Next()
	}
}
